#!/bin/bash

# Redis Cluster Production Initialization Script
# =============================================
#redis-cli -a Redis@2024#Prod --cluster create 192.168.5.7:6001 192.168.5.7:6002 192.168.5.7:6003 192.168.5.7:6004 192.168.5.7:6005 192.168.5.7:6006 --cluster-replicas 1
#redis-cli -a Redis@2024#Prod -c
#cluster info
set -e
# Configuration
REDIS_PASSWORD="Redis@2024#Prod"
REDIS_NODES=(
    "173.18.0.11:6379"
    "173.18.0.12:6379"
    "173.18.0.13:6379"
    "173.18.0.14:6379"
    "173.18.0.15:6379"
    "173.18.0.16:6379"
)

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Logging function
log() {
    echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}

warn() {
    echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}"
}

error() {
    echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
}

# Check if Redis CLI is available
check_redis_cli() {
    if ! command -v redis-cli &> /dev/null; then
        error "redis-cli is not installed or not in PATH"
        exit 1
    fi
}

# Wait for Redis node to be ready
wait_for_redis() {
    local node=$1
    local max_attempts=30
    local attempt=1
    
    log "Waiting for Redis node $node to be ready..."
    
    while [ $attempt -le $max_attempts ]; do
        if redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD ping &> /dev/null; then
            log "Redis node $node is ready"
            return 0
        fi
        
        echo -n "."
        sleep 2
        ((attempt++))
    done
    
    error "Redis node $node failed to start within $max_attempts attempts"
    return 1
}

# Check if cluster is already initialized
check_cluster_status() {
    local node=${REDIS_NODES[0]}
    local cluster_info
    
    cluster_info=$(redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD cluster info 2>/dev/null || echo "")
    
    if [[ $cluster_info == *"cluster_state:ok"* ]]; then
        log "Redis cluster is already initialized and healthy"
        return 0
    elif [[ $cluster_info == *"cluster_state:fail"* ]]; then
        warn "Redis cluster exists but is in failed state"
        return 1
    else
        log "Redis cluster is not initialized"
        return 2
    fi
}

# Initialize Redis cluster
init_cluster() {
    log "Initializing Redis cluster..."
    
    # Create cluster command
    local cluster_cmd="redis-cli --cluster create"
    for node in "${REDIS_NODES[@]}"; do
        cluster_cmd="$cluster_cmd $node"
    done
    cluster_cmd="$cluster_cmd --cluster-replicas 1 --cluster-yes -a $REDIS_PASSWORD"
    
    log "Executing: $cluster_cmd"
    
    if eval $cluster_cmd; then
        log "Redis cluster initialized successfully"
        return 0
    else
        error "Failed to initialize Redis cluster"
        return 1
    fi
}

# Fix cluster if needed
fix_cluster() {
    log "Attempting to fix Redis cluster..."
    
    local node=${REDIS_NODES[0]}
    
    # Check cluster nodes
    log "Current cluster nodes:"
    redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD cluster nodes
    
    # Try to fix cluster
    if redis-cli --cluster fix ${REDIS_NODES[0]} --cluster-yes -a $REDIS_PASSWORD; then
        log "Cluster fix completed"
        return 0
    else
        error "Failed to fix cluster"
        return 1
    fi
}

# Verify cluster health
verify_cluster() {
    log "Verifying cluster health..."
    
    local node=${REDIS_NODES[0]}
    local cluster_info
    
    cluster_info=$(redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD cluster info)
    
    if [[ $cluster_info == *"cluster_state:ok"* ]]; then
        log "✓ Cluster state: OK"
    else
        error "✗ Cluster state: FAILED"
        return 1
    fi
    
    # Check cluster size
    local cluster_size=$(echo "$cluster_info" | grep "cluster_size:" | cut -d: -f2 | tr -d '\r')
    if [ "$cluster_size" = "6" ]; then
        log "✓ Cluster size: $cluster_size nodes"
    else
        warn "⚠ Cluster size: $cluster_size nodes (expected 6)"
    fi
    
    # Check cluster slots assignment
    local slots_assigned=$(echo "$cluster_info" | grep "cluster_slots_assigned:" | cut -d: -f2 | tr -d '\r')
    if [ "$slots_assigned" = "16384" ]; then
        log "✓ Cluster slots assigned: $slots_assigned/16384"
    else
        warn "⚠ Cluster slots assigned: $slots_assigned/16384"
    fi
    
    # Test cluster connectivity
    log "Testing cluster connectivity..."
    local test_key="test_key_$(date +%s)"
    local test_value="cluster_test_value"
    
    if redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD set $test_key $test_value &> /dev/null; then
        local retrieved_value=$(redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD get $test_key 2>/dev/null)
        if [ "$retrieved_value" = "$test_value" ]; then
            log "✓ Cluster read/write test passed"
            redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD del $test_key &> /dev/null
        else
            error "✗ Cluster read/write test failed"
            return 1
        fi
    else
        error "✗ Failed to write test key to cluster"
        return 1
    fi
    
    log "Cluster verification completed successfully"
    return 0
}

# Show cluster information
show_cluster_info() {
    local node=${REDIS_NODES[0]}
    
    log "Cluster Information:"
    echo "=================="
    redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD cluster info
    echo ""
    
    log "Cluster Nodes:"
    echo "============="
    redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD cluster nodes
    echo ""
    
    log "Memory Usage:"
    echo "============"
    redis-cli -h ${node%:*} -p ${node#*:} -a $REDIS_PASSWORD info memory | grep used_memory_human
}

# Main execution
main() {
    log "Starting Redis Cluster Production Initialization"
    log "================================================"
    
    # Check prerequisites
    check_redis_cli
    
    # Wait for all nodes to be ready
    log "Waiting for all Redis nodes to be ready..."
    for node in "${REDIS_NODES[@]}"; do
        wait_for_redis $node || exit 1
    done
    
    # Check current cluster status
    local cluster_status
    check_cluster_status
    cluster_status=$?
    
    case $cluster_status in
        0)
            log "Cluster is already healthy"
            verify_cluster
            show_cluster_info
            ;;
        1)
            log "Cluster exists but needs fixing"
            fix_cluster || init_cluster
            verify_cluster
            show_cluster_info
            ;;
        2)
            log "Initializing new cluster"
            init_cluster || exit 1
            verify_cluster
            show_cluster_info
            ;;
    esac
    
    log "Redis Cluster initialization completed successfully!"
    log "=================================================="
    log "Connection string: redis://:${REDIS_PASSWORD}@${REDIS_NODES[0]}"
    log "Use 'redis-cli -c -h ${REDIS_NODES[0]%:*} -p ${REDIS_NODES[0]#*:} -a $REDIS_PASSWORD' to connect"
}

# Handle script interruption
trap 'error "Script interrupted"; exit 1' INT TERM

# Run main function
main "$@"